package gbif.common.dal;

import gbif.common.dal.finder.FinderExecutor;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.ScrollableResults;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;


@SuppressWarnings({"unchecked","rawtypes"})
public class FinderBase<T> extends HibernateDaoSupport implements Serializable, FinderExecutor<T>{

	 /**
	 * 
	 */
	private static final long serialVersionUID = 6163830391676675282L;


	private Query prepareQuery(Method method, Object[] queryArgs)
	    {
	        final String queryName = this.queryNameFromMethod(method);
	        final Query namedQuery = getSession().getNamedQuery(queryName);
	        String[] namedParameters = namedQuery.getNamedParameters();
	        if(namedParameters.length==0)
	        {
	            setPositionalParams(queryArgs, namedQuery);
	        } else {
	            setNamedParams(namedParameters, queryArgs, namedQuery);
	        }
	        return namedQuery;
	    }

	    private void setPositionalParams(Object[] queryArgs, Query namedQuery)
	    {
	        // Set parameter. Use custom Hibernate Type if necessary
	        if(queryArgs!=null)
	        {
	            for(int i = 0; i < queryArgs.length; i++)
	            {
	                Object arg = queryArgs[i];    
	                namedQuery.setParameter(i, arg);	               
	            }
	        }
	    }

	    private void setNamedParams(String[] namedParameters, Object[] queryArgs, Query namedQuery)
	    {
	        // Set parameter. Use custom Hibernate Type if necessary
	        if(queryArgs!=null)
	        {
	            for(int i = 0; i < queryArgs.length; i++)
	            {
	                Object arg = queryArgs[i];	                
                 if(arg instanceof Collection) {
                     namedQuery.setParameterList(namedParameters[i], (Collection) arg);
                 }
                 else
                 {
                     namedQuery.setParameter(namedParameters[i], arg);
                 }	                
	            }
	        }
	    }

	public List<T> executeFinder(Method method, final Object[] queryArgs) {
		final org.hibernate.Query namedQuery = prepareQuery(method,
				queryArgs);
		return (List<T>) namedQuery.list();
	}
	
	public Iterator<T> iterateFinder(Method method, final Object[] queryArgs) {
		final org.hibernate.Query namedQuery = prepareQuery(method,
				queryArgs);
		return (Iterator<T>) namedQuery.iterate();
	}
	
	public ScrollableResults scrollFinder(Method method, final Object[] queryArgs) {
		final org.hibernate.Query namedQuery = prepareQuery(method,
				queryArgs);
		return namedQuery.scroll();
	}

	
	public String queryNameFromMethod(Method finderMethod) {	
		return finderMethod.getDeclaringClass().getSimpleName() + "." + finderMethod.getName();
	}
}
